feat(java): read idempotency-key generation config from the IR#17012
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
There was a problem hiding this comment.
AI Review Summary
Ports the auto-generate idempotency key feature to the Java SDK generator. Implementation is clean and follows existing conventions. One notable resource leak in the generator's error path and a minor thread-safety observation on the config flag boxing.
- 🔵 1 suggestion(s)
| } catch (IOException e) { | ||
| throw new RuntimeException("Failed to read IdempotencyUtils.java"); |
There was a problem hiding this comment.
🔵 suggestion
The original IOException is swallowed — chain it for debuggability.
| } catch (IOException e) { | |
| throw new RuntimeException("Failed to read IdempotencyUtils.java"); | |
| } catch (IOException e) { | |
| throw new RuntimeException("Failed to read IdempotencyUtils.java", e); |
There was a problem hiding this comment.
Done — chained the cause in 42b7a48: throw new RuntimeException("Failed to read IdempotencyUtils.java", e);.
SDK Generation Benchmark ResultsComparing PR branch against median of 5 nightly run(s) on Full benchmark table (click to expand)
main (generator): generator-only time via --skip-scripts (includes Docker image build, container startup, IR parsing, and code generation — this is the same Docker-based flow customers use via |
df4de3f to
a3f3815
Compare
Docs Generation Benchmark ResultsComparing PR branch against median of 5 nightly run(s) on
Docs generation runs |
Drive idempotency-key auto-generation from ir.getSdkConfig().getIdempotencyKeyGeneration() instead of a per-generator config flag. The header name and eligible HTTP methods come from the IR; a caller-supplied key always wins, otherwise a UUIDv4 is generated. Output is byte-identical when the feature is disabled. Depends on #17027 (IR v67 upgrade). Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
42b7a48 to
f6dab18
Compare
… idempotency resolver conflict in favor of main (global api.settings support) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
Devin is archived and cannot be woken up. Please unarchive Devin if you want to continue using it. |
5 similar comments
|
Devin is archived and cannot be woken up. Please unarchive Devin if you want to continue using it. |
|
Devin is archived and cannot be woken up. Please unarchive Devin if you want to continue using it. |
|
Devin is archived and cannot be woken up. Please unarchive Devin if you want to continue using it. |
|
Devin is archived and cannot be woken up. Please unarchive Devin if you want to continue using it. |
|
Devin is archived and cannot be woken up. Please unarchive Devin if you want to continue using it. |
…ator Post-merge regeneration of the full java-sdk seed suite (189/189 pass) so snapshots reflect current-main generator output plus the FER-11565 null-guards. Changes decompose into: - ClientOptions.Builder.addHeader null-skip guard (FER-11565 guard #2) applied to the idempotency and java-oauth-token-optional fixtures whose snapshots predated the guard. - main's idempotency-key IR-driven refactor (#17012): IdempotencyUtils removed, Raw*Client no longer wraps headers with withGeneratedIdempotencyKey. - main's OAuth token-request change (#17076): inferred-auth-implicit GetTokenRequest client_secret now Optional. Co-Authored-By: Claude <noreply@anthropic.com>
…es FER-11565) (#17069) * fix(java): guard null api-key header on OAuth-only construction (FER-11565) Under multi-scheme (`any`) auth combining OAuth client-credentials with an api-key header, constructing a client with OAuth creds only (via `withCredentials(...)`, no `.apiKey(...)`) baked a `null` api-key header into `ClientOptions`. okhttp `Headers.of` then NPE'd on the first HTTP call (the token fetch), because the `_CredentialsAuth` path never sets `apiKey` and bypasses the builder's build()-time null validation. Fix, in the Java SDK generator: - AbstractRootClientGenerator.visitHeaderBase: emit an `if (this.<field> != null)` guard around the header add for any non-literal header credential (previously only optional-container headers were guarded). The api-key-only builder still validates non-null in build(), so the runtime guard is harmless there. - ClientOptionsGenerator.getHeaderBuilder: the generated `ClientOptions.Builder.addHeader(String, String)` now defensively skips null values, so no codegen path can bake a null header. Supplying both an apiKey and OAuth creds under `any` still sends both the api-key header and `Authorization: Bearer`. Closes FER-11565 Co-Authored-By: Claude <noreply@anthropic.com> * chore(seed): regenerate java-sdk snapshots against current-main generator Post-merge regeneration of the full java-sdk seed suite (189/189 pass) so snapshots reflect current-main generator output plus the FER-11565 null-guards. Changes decompose into: - ClientOptions.Builder.addHeader null-skip guard (FER-11565 guard #2) applied to the idempotency and java-oauth-token-optional fixtures whose snapshots predated the guard. - main's idempotency-key IR-driven refactor (#17012): IdempotencyUtils removed, Raw*Client no longer wraps headers with withGeneratedIdempotencyKey. - main's OAuth token-request change (#17076): inferred-auth-implicit GetTokenRequest client_secret now Optional. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Fern Support <support@buildwithfern.com> Co-authored-by: Claude <noreply@anthropic.com>
Description
Makes the v1 Java SDK generator's idempotency-key feature IR-driven. Instead of a per-generator
generators.ymlconfig flag with hardcodedIdempotency-Key/POST/PUT, the generator now readsir.getSdkConfig().getIdempotencyKeyGeneration():IdempotencyKeyGeneration.getHeaderName()(no longer hardcoded).IdempotencyKeyGeneration.getMethods()(no longer hardcoded POST/PUT).Runtime behavior is preserved: a caller-supplied key always wins, otherwise a fresh
UUID.randomUUID()is generated. When the feature is disabled, generated output is byte-identical to before (maybeWrapHeadersWithIdempotencyKeyreturns the original headers expression unchanged).Changes Made
AbstractEndpointWriter.java: addedidempotencyKeyGenerationForEndpoint()(filters the IR config by the endpoint's HTTP method) andmaybeWrapHeadersWithIdempotencyKey(...); all four header-emitting sites now route through it.NoRequestEndpointWriter.java/OnlyRequestEndpointWriter.java/WrappedRequestEndpointWriter.java: header emission wrapped via the same helper.Cli.java: emitIdempotencyUtilsonly whengetSdkConfig().getIdempotencyKeyGeneration().isPresent().IdempotencyUtilsGenerator.java+resources/IdempotencyUtils.java: runtime helperwithGeneratedIdempotencyKey(Map<String,String> headers, String headerName)(UUIDv4,putIfAbsentso caller wins). Header name is a parameter, not hardcoded.autoGenerateIdempotencyKey).packages/commons/api-workspace-commons/src/checkVersionExists.ts:getGeneratorConfigObject()helper so the seed synthetic invocation can thread theauto-generate-idempotency-keyconfig into the IR (falls back to the resolved config when no raw block is present).idempotency-headersandjava-idempotency-headers-file-uploadnow each generate anauto-generate-idempotency-keyvariant (via the kebab CLI key) alongside the off variant. Off variants are byte-identical tomain.Testing
pnpm seed test --generator java-sdk --fixture idempotency-headers --fixture java-idempotency-headers-file-upload --skip-scripts— 4/4 pass.createwraps headers withIdempotencyUtils.withGeneratedIdempotencyKey(..., "Idempotency-Key"); DELETE does not (method-gating works).no-custom-config,default) byte-identical to base.